package com.atguigu.tingshu.album.service.impl;
import java.math.BigDecimal;
import java.util.Date;

import com.atguigu.tingshu.album.mapper.*;
import com.atguigu.tingshu.album.service.AlbumAttrValueService;
import com.atguigu.tingshu.album.service.BaseCategoryService;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.album.*;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.google.common.collect.Maps;

import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.asn1.crmf.AttributeTypeAndValue;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

	@Autowired
	private AlbumInfoMapper albumInfoMapper;
    @Autowired
    private AlbumAttributeValueMapper albumAttributeValueMapper;

    @Autowired
    private AlbumStatMapper albumStatMapper;

    @Autowired
    private AlbumAttrValueService  albumAttrValueService;

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    @Autowired
    private BaseCategory1Mapper baseCategory1Mapper;
    @Autowired
    private BaseCategory2Mapper baseCategory2Mapper;
    @Autowired
    private BaseCategory3Mapper baseCategory3Mapper;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;
    @Override
    /*spring事务默认只能感知运行时异常
    rollbackFor:回滚,对 Exception类型的异常回滚 为了保证原子性，开启事务*/
    @Transactional(rollbackFor = Exception.class)
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo) {

        /*获取调用这个方法的代理对象(上下文获取)
        * 注意:还需要在启动类中使用@EnableAspectJAutoProxy(proxyTargetClass = true)
        * */
        AlbumInfoServiceImpl proxyObject = (AlbumInfoServiceImpl) AopContext.currentProxy();

        // 保存专辑信息,基本信息albumInfo
        AlbumInfo albumInfo = new AlbumInfo();
        BeanUtils.copyProperties(albumInfoVo, albumInfo);
        albumInfo.setUserId(AuthContextHolder.getUserId());
        albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
        //判断专辑的付费类型
        if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfoVo.getPayType())){
            // 设置免费试听集数,默认5
          albumInfo.setTracksForFree(5);
        }
        albumInfoMapper.insert(albumInfo);

        //保存专辑的标签信息到专辑属性值表album_attribute_value
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        if (!CollectionUtils.isEmpty(albumAttributeValueVoList)){
            for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
                AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                albumAttributeValue.setAlbumId(albumInfo.getId());
                albumAttributeValue.setValueId(albumAttributeValueVo.getValueId());
                albumAttributeValue.setAttributeId(albumAttributeValueVo.getAttributeId());
                albumAttributeValueMapper.insert(albumAttributeValue);
            }
        }

        //3.初始化专辑统计表 album_stat表中插入数据
        //用代理对象调用初始化方法
        proxyObject.initAlbumStat(albumInfo.getId());

        //4.将专辑保存到es中
        if ("1".equals(albumInfoVo.getIsOpen())) {
            //方法一:rpc调用搜索微服务,上架这个专辑
            //方法二(更好):异步发送一个消息给消息队列,队列的消费者监听到这个消息,然后上架这个专辑
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_UPPER,albumInfo.getId().toString());
            log.info("专辑微服务发送消息内容:{}到搜索微服务对应的队列中成功......");
        }
    }

    /**
     * 分页查询用户专辑信息
     * @param albumListVoPage
     * @param albumInfoQuery
     * @return
     */
    @Override
    public IPage<AlbumListVo> findUserAlbumPage(IPage<AlbumListVo> albumListVoPage, AlbumInfoQuery albumInfoQuery) {


        return albumInfoMapper.findUserAlbumPage(albumListVoPage, albumInfoQuery);
    }

    @Override
    public AlbumInfo getAlbumInfo(Long albumId) {
        //1.查询基础属性
        AlbumInfo albumInfo = baseMapper.selectById(albumId);
        if (albumInfo == null){
            throw new GuiguException(201,"专辑不存在");
        }
        //2.给Album_Info的标签属性赋值
        //查询标签属性
        List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueMapper.selectList(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId,albumId));
        albumInfo.setAlbumAttributeValueVoList(albumAttributeValueList);

        return albumInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAlbumInfo(AlbumInfoVo albumInfoVo, Long albumId, Long userId) {
        //1.修改专辑基本信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null){
            throw new GuiguException(201,"专辑不存在");
        }
        BeanUtils.copyProperties(albumInfoVo,albumInfo);

        String payType = albumInfoVo.getPayType();
        if (SystemConstant.ALBUM_PAY_TYPE_FREE.equals(payType)){
            albumInfo.setPrice(new BigDecimal("0.00")); //清空价格
            albumInfo.setDiscount(new BigDecimal("-1.00"));//清空折扣力度
            albumInfo.setVipDiscount(new BigDecimal("-1.00"));//清空vip折扣力度
            albumInfo.setTracksForFree(0);//清空免费试听集数
        }else {
            albumInfo.setTracksForFree(5);//设置初始费试听集数
        }


        albumInfoMapper.updateById(albumInfo);
        //2.修改标签信息
        //2.1删除原来的标签信息
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId,albumId));
        //3.插入新标签信息
        List<AlbumAttributeValue> newalbumAttributeValueList = albumInfoVo.getAlbumAttributeValueVoList().stream().map(albumAttributeValueVo -> {
            AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
            albumAttributeValue.setAlbumId(albumId);
            albumAttributeValue.setAttributeId(albumAttributeValueVo.getAttributeId());
            albumAttributeValue.setValueId(albumAttributeValueVo.getValueId());
            return albumAttributeValue;
        }).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(newalbumAttributeValueList)){
            albumAttrValueService.saveBatch(newalbumAttributeValueList);
        }

        if ("1".equals(albumInfoVo.getIsOpen())){
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_UPPER,albumInfo.getId().toString());
            log.info("专辑微服务发送消息内容:{}到搜索微服务对应的队列中成功......",albumInfo.getId());
        }else {
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_LOWER,albumInfo.getId().toString());
            log.info("专辑微服务发送消息内容:{}到搜索微服务对应的队列中成功......",albumInfo.getId());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removremoveAlbumInfoeById(Long userId, Long albumId) {
        //删除基本信息
        Long count = trackInfoMapper.selectCount(new LambdaQueryWrapper<TrackInfo>().eq(TrackInfo::getAlbumId, albumId));
        if (count > 0){
            throw new GuiguException(201,"专辑下有声音，不能删除");
        }
        albumInfoMapper.deleteById(albumId);
        //删除标签信息
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId));
        //删除统计信息
        albumStatMapper.delete(new LambdaQueryWrapper<AlbumStat>().eq(AlbumStat::getAlbumId, albumId));

        //将专辑从es中下架
        rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_LOWER,albumId.toString());
        log.info("专辑微服务发送消息内容:{}到搜索微服务对应的队列中成功......",albumId);
    }

    /**
     * 查询用户所有专辑列表
     * @param userId
     * @return
     */
    @Override
    public List<AlbumInfo> findUserAllAlbumList(Long userId) {
        List<AlbumInfo> albumInfoList = albumInfoMapper.selectList(new LambdaQueryWrapper<AlbumInfo>().eq(AlbumInfo::getUserId, userId));
        return albumInfoList;
    }

    /**
     * 获取专辑分类信息
     * @param albumId
     * @return
     */
    @Override
    public BaseCategoryView getAlbumInfoCatergoryView(Long albumId) {
        return baseCategory1Mapper.getAlbumInfoCatergoryView(albumId);
    }

    @Override
    public AlbumStatVo getAlbumStatNum(Long albumId) {
        return albumStatMapper.getAlbumStatNum(albumId);
    }


    /**
     * 判断并且过滤真正购买的声音列表
     * @param userId
     * @param itemId
     * @param trackCount
     * @return
     */
    @Override
    public List<TrackInfo> checkAndFilterTrackList(Long userId, Long itemId, Integer trackCount) {

        List<TrackInfo> result = new ArrayList<>();
        //1.根据声音id查询声音信息
        TrackInfo trackInfo = trackInfoMapper.selectById(itemId);
        if (trackInfo == null){
            throw new GuiguException(201,"声音不存在");
        }
        //2.获取专辑id
        Long albumId = trackInfo.getAlbumId();
        //3获取专辑对象
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null){
            throw new GuiguException(201,"专辑不存在");
        }
        //4.查询用户买过的声音合集
        Result<Map<Long, String>> userPaidAlbumTrackList = userInfoFeignClient.getUserPaidAlbumTrackList(albumId, userId);
        Map<Long, String> paidAlbumTrackListData = userPaidAlbumTrackList.getData();
        Assert.notNull(paidAlbumTrackListData,"远程调用用户微服务获取用户买过的声音合集失败");

        //5.查询需要买的声音列表
        if (trackCount!=0){
            result= trackInfoMapper.selectList(new LambdaQueryWrapper<TrackInfo>()
                    .eq(TrackInfo::getAlbumId, albumId)
                    .gt(TrackInfo::getOrderNum, trackInfo.getOrderNum())
                    .orderByAsc(TrackInfo::getOrderNum)
                    .last("limit " + trackCount));
        }else {
            result.add(trackInfo);
        }

        //6.过滤
        result.stream().forEach(track->{
            if (!StringUtils.isEmpty(paidAlbumTrackListData.get(track.getId()))){
                throw new GuiguException(201,"专辑下有声音已购买,不能重复购买");
            }
        });

        return result;
    }

    @Override
    public TrackInfo getTrackInfoByTrackId(Long itemId) {
        TrackInfo trackInfo = trackInfoMapper.selectById(itemId);
        return trackInfo;
    }


    /**
     * 初始化专辑统计表
     * @param albumId
     */

    /*
    在同一个类的有2个方法都加了@Transactional注解，
    在第1个方法中调用第2个方法,
    需要用代理对象调用第2个放法,不用代理对象会失效*/
    @Transactional(rollbackFor = Exception.class) //为了保证原子性，开启事务
    public void initAlbumStat(Long albumId) {
        //将四种维度统计放到一个集合中
        ArrayList<String> dimensions = new ArrayList<>();
        dimensions.add(SystemConstant.ALBUM_STAT_PLAY);
        dimensions.add(SystemConstant.ALBUM_STAT_SUBSCRIBE);
        dimensions.add(SystemConstant.ALBUM_STAT_BROWSE);
        dimensions.add(SystemConstant.ALBUM_STAT_COMMENT);

        for (String dimension : dimensions){
            AlbumStat albumStat = new AlbumStat();
            albumStat.setAlbumId(albumId);
            albumStat.setStatType(dimension);
            albumStat.setStatNum(0);
            albumStatMapper.insert(albumStat);

        }




    }
}
